/**
 * 需求点： 在连续的事件触发下，只响应一次。
 * @param fuc
 * @param wait
 * @returns
 */

const debounce = (fuc, wait) => {
	let timeId
	let leading = true
	let trailing = false

	let lastThis
	let lastArgs
	let result
	let lastInvokingTime
	let lastCallBackTime

	const invoFun = time => {
		lastInvokingTime = time
		let currentThis = lastThis
		let currentArgs = lastArgs

		lastArgs = lastThis = undefined
		result = fuc.apply(currentThis, currentArgs)
		return result
	}
	const startTime = (func, wait) => {
		return setTimeout(func, wait)
	}

	// 1. 当前无time的时候，需要触发
	// 2. 超过wait时间的时候需要触发
	// 3. 当用户人为的想要立即触发，等待时间为负数
	const shouldInvoing = (time: number) => {
		const timeSinceCallBackTime = time - lastCallBackTime

		return (
			timeId === undefined ||
			timeSinceCallBackTime > wait ||
			timeSinceCallBackTime < 0
		)
	}

	const trailingEdge = time => {
		timeId = undefined

		if (lastArgs && trailing) {
			return invoFun(time)
		}
		lastArgs = lastThis = undefined
		return result
	}
	// 是否立即触发
	const leadingEdge = (time: number) => {
		lastInvokingTime = time
		timeId = startTime(timerExpired, wait)
		return leading ? invoFun(time) : result
	}

	const timerExpired = () => {
		const time = Date.now()
		if (shouldInvoing(time)) {
			return trailingEdge(time)
		}

		timeId = startTime(timerExpired, wait)
		return undefined
	}

	const debounced = (...args) => {
		const time = Date.now()
		const isInvoking = shouldInvoing(time)

		lastCallBackTime = time
		lastThis = this
		lastArgs = args

		if (isInvoking) {
			if (timeId === undefined) {
				return leadingEdge(time)
			}
		}

		if (timeId === undefined) {
			timeId = startTime(timerExpired, wait)
		}

		return result
	}

	return debounced
}

export default debounce
